"""
模型构建与训练
Sequential 模型结构： 层（layers）的线性堆栈，它是一个简单的线性结构，没有多余分支，是多个网络层的堆叠
多少个滤波器就输出多少个特征图，即卷积核(滤波器)的深度
3通道RGB图片，一个滤波器有3个通道的小卷积核，但还是只算1个滤波器
"""
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
#Flatten层用来将输入“压平”，即把多维的输入一维化，
#常用在从卷积层到全连接层的过渡
from keras.layers import Flatten
from keras.layers.convolutional import Conv2D
from keras.layers.convolutional import MaxPooling2D

#模拟原始灰度数据读入
img_size=28
num=10
mnist=input_data.read_data_sets("./data",one_hot=True)
X_train,y_train,X_test,y_test=mnist.train.images,mnist.train.labels,mnist.test.images,mnist.test.labels
X_train=X_train.reshape(-1,img_size,img_size)
X_test=X_test.reshape(-1,img_size,img_size)
X_train=X_train*255
X_test=X_test*255
y_train=y_train.reshape(-1,num)
y_test=y_test.reshape(-1,num)
print(X_train.shape) #(55000, 28, 28)
print(y_train.shape) #(55000, 10)

#此处卷积输入的形状要与模型中的input_shape匹配
X_train = X_train.reshape(X_train.shape[0],28,28,1).astype('float32')
X_test = X_test.reshape(X_test.shape[0],28,28,1).astype('float32')
print(X_train.shape)#(55000,28,28,1)

#归一化
X_train=X_train/255
X_test=X_test/255

# one hot编码,这里编好了，省略
#y_train = np_utils.to_categorical(y_train)
#y_test = np_utils.to_categorical(y_test)

#搭建CNN网络
def CNN():
    """
    第一层是卷积层。该层有32个feature map，作为模型的输入层，接受[pixels][width][height]大小的输入数据。feature map的大小是1*5*5，其输出接一个‘relu’激活函数
    下一层是pooling层，使用了MaxPooling，大小为2*2
    Flatten压缩一维后作为全连接层的输入层
    接下来是全连接层，有128个神经元，激活函数采用‘relu’
    最后一层是输出层，有10个神经元，每个神经元对应一个类别，输出值表示样本属于该类别的概率大小
    """
    model = Sequential()
    model.add(Conv2D(32, (5, 5), input_shape=(img_size,img_size,1), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Flatten())
    model.add(Dense(128, activation='relu'))
    model.add(Dense(num, activation='softmax'))
    #编译
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
    return model

#模型训练
model=CNN()
model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=5, batch_size=200, verbose=1)
model.summary()
scores = model.evaluate(X_test,y_test,verbose=1)
print(scores)

#模型保存
model_dir="./CNN.h5"
model.save(model_dir)